home *** CD-ROM | disk | FTP | other *** search
- /* -------------- xmodem.c --------------- */
- #include <stdio.h>
- #include <conio.h>
- #include <stdlib.h>
- #include <mem.h>
- #include "window.h"
- #include "serial.h"
-
- #define RETRIES 12
- #define CRCTRIES 2
- #define PADCHAR 0x1a
- #define SOH 1
- #define EOT 4
- #define ACK 6
- #define NAK 0x15
- #define CAN 0x18
- #define CRC 'C'
- /* -------- external data ---------- */
- extern int TIMEOUT;
- extern int WORDLEN;
- extern int xonxoff_enabled;
- /* --------- local data ------------ */
- static int tries; /* retry counter */
- static char bf [130]; /* i/o buffer */
- /* -------- prototypes ------------- */
- extern int keyhit(void);
- static void receive_error(int, int);
- static void xmodem_msg(char *);
- static void test_wordlen(void);
- unsigned compute_crc(char *, int);
- /* --------- error messages ----------- */
- static char *errs[] = {
- "Timed Out ",
- "Invalid SOH ",
- "Invalid block # ",
- "Invalid chksum/crc"
- };
- /* ---------- upload with xmodem protocol ------------- */
- void upload_xmodem(FILE *fd)
- {
- int i, chksum, eof = FALSE, ans = 0, ln, crcout = 0;
- unsigned crc;
- char bno = 1;
- xonxoff_enabled = FALSE;
- establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
- window_title("XMODEM Upload (CHKSUM)");
- tries = 0;
- test_wordlen();
- /* ----- wait for the go-ahead from the receiver ------ */
- TIMEOUT = 6;
- while (tries++ < RETRIES && crcout != NAK && crcout != CRC)
- crcout = readcomm();
- if (crcout == CRC)
- window_title(" XMODEM Upload (CRC) ");
- TIMEOUT = 10;
- /* -------- send the file to the receiver ----------- */
- while (tries < RETRIES &&
- !eof && ans != CAN && !timed_out()) {
- /* ---- read the next data block ----- */
- setmem(bf, 128, PADCHAR);
- if ((ln = fread(bf, 1, 128, fd)) < 128)
- eof = TRUE;
- if (ln == 0)
- break;
- gotoxy(2, 2);
- cprintf("Block %d ",bno);
- chksum = 0;
- if (keyhit())
- if (getch() == ESC) {
- writecomm(CAN);
- break;
- }
- writecomm(SOH); /* SOH */
- writecomm(bno); /* block number */
- writecomm(~bno); /* 1s complement */
- /* ------- send the data block ------ */
- for (i = 0; i < 128; i++) {
- writecomm(bf[i]);
- chksum += bf[i]; /* checksum calculation */
- }
- /* -- send error-correcting value (chksum or crc) -- */
- if (crcout == NAK)
- writecomm(chksum & 255);
- else {
- crc = compute_crc(bf, 130);
- writecomm((crc >> 8) & 255);
- writecomm(crc & 255);
- }
- /* ----- read ACK, NAK, or CAN from receiver ----- */
- ans = readcomm();
- if (ans == ACK) {
- bno++;
- tries = 0;
- gotoxy(2, 4);
- cprintf(" ");
- }
- if (ans == NAK) {
- eof = FALSE;
- gotoxy(2, 4);
- cprintf("%2d tries", ++tries);
- /* ---- position to previous block ----- */
- if (fseek(fd, -128L, 1) == -1)
- fseek(fd, 0L, 0);
- }
- }
- if (eof) {
- writecomm(EOT); /* send the EOT */
- readcomm(); /* wait for an ACK */
- xmodem_msg("Transfer Completed");
- }
- else
- xmodem_msg("Transfer Aborted");
- xonxoff_enabled = TRUE;
- }
- /* ---------- download with xmodem protocol ------------- */
- void download_xmodem(FILE *fd)
- {
- int blk=0, soh= 0, bn, nbn, i, crcin = TRUE, fst = TRUE;
- unsigned chksum, cs, cs1;
- xonxoff_enabled = FALSE;
- establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
- window_title("XMODEM Download (CHKSUM)");
- /* - send Cs then NAKs until the sender starts sending - */
- tries = 0;
- test_wordlen();
- TIMEOUT = 6;
- while (soh != SOH && tries < RETRIES) {
- crcin = (tries++ < CRCTRIES);
- writecomm(crcin ? CRC : NAK);
- soh = readcomm();
- if (!timed_out() && soh != SOH)
- sleep(6);
- }
- if (crcin)
- window_title(" XMODEM Download (CRC) ");
- while (tries < RETRIES) {
- if (timed_out())
- receive_error(0, NAK);
- /* -- Receive the data and build the file -- */
- gotoxy(2,2);
- cprintf("Block %d ", blk + 1);
- if (!fst) {
- TIMEOUT = 10;
- soh = readcomm();
- if (timed_out())
- continue;
- if (soh == CAN)
- break;
- if (soh == EOT) {
- writecomm(ACK);
- break;
- }
- }
- fst = FALSE;
- TIMEOUT = 1;
- bn = readcomm() & 255; /* block number */
- nbn = readcomm() & 255; /* 1's complement */
- chksum = 0;
- /* ---- data block ----- */
- for (i = 0; i < 128; i++) {
- *(bf + i) = readcomm();
- if (timed_out())
- break;
- chksum = (chksum + (*(bf + i)) & 255) & 255;
- }
- if (timed_out())
- continue;
- /* ---- checksum or crc from sender ---- */
- cs = readcomm() & 255;
- if (crcin) {
- cs1 = readcomm() & 255;
- cs = (cs << 8) + cs1;
- }
- if (timed_out())
- continue;
- if (soh != SOH) { /* check the SOH */
- receive_error(1, NAK);
- continue;
- }
- /* --- same as previous block number? --- */
- if (bn == blk)
- fseek(fd, -128L, 1);
- /* --- no, next sequential block number? --- */
- else if (bn != ((blk + 1) & 255)) {
- receive_error(2, CAN);
- break;
- }
- blk = bn;
- /* --- test the block # 1s complement --- */
- if ((nbn & 255) != (~blk & 255)) {
- receive_error(2, NAK);
- continue;
- }
- if (crcin)
- chksum = compute_crc(bf, 130);
- /* --- test chksum or crc vs one sent --- */
- if (cs != chksum) {
- receive_error(6, NAK);
- continue;
- }
- soh = bn = nbn = cs = 0;
- tries = 0;
- /* --- write the block to disk --- */
- fwrite(bf, 128, 1, fd);
- if (keyhit())
- if (getch() == ESC) {
- writecomm(CAN);
- break;
- }
- writecomm(ACK);
- }
- if (soh == EOT)
- xmodem_msg("Transfer Complete");
- else
- xmodem_msg("Transfer Aborted");
- TIMEOUT = 10;
- xonxoff_enabled = TRUE;
- }
- /* ------------- send a nak ------------ */
- static void receive_error(erno, rtn)
- {
- ++tries;
- if (TIMEOUT == 1) {
- gotoxy(2,4);
- cprintf("%s (%d tries)", errs[erno], tries);
- }
- writecomm(rtn);
- }
- /* ------ test for valid word length -------- */
- static void test_wordlen(void)
- {
- if (WORDLEN != 8) {
- gotoxy(2,4);
- cprintf("Must be 8 Data Bits");
- tries = RETRIES;
- }
- }
- /* --------- final message about xmodem transfer -------- */
- static void xmodem_msg(char *s)
- {
- gotoxy(2,3);
- cprintf(s);
- putch(BELL);
- sleep(3);
- delete_window();
- }
- /* --------- compute the crc ------------ */
- unsigned compute_crc(char *bf, int len)
- {
- int i;
- long crc = 0;
- while (len--) {
- crc |= (*bf++) & 255;
- for (i = 0; i < 8; i++) {
- crc <<= 1;
- if (crc & 0x1000000L)
- crc ^= 0x102100L;
- }
- }
- return (unsigned) (crc >> 8);
- }